unit UART;

{$mode ObjFPC}{$H+}
{$IF DEFINED(DEBUG) or DEFINED(DEBUG_UART)}
  {$L uart.c-debug.obj}
{$ELSE}
  {$L uart.c.obj}
{$ENDIF}

interface

uses HAL;

type
  TUART = (UART_0, UART_1);
  TDATABITS = (FIVE, SIX, SEVEN, EIGHT);
  TPARITY = (NONE, EVEN, ODD);
  TSTOPBITS = (ONE, TWO);

  CUART = class;
  TISR_UART = procedure (UARTx: CUART; DAT: Byte);

  CUART = class
  private
    FREG: ^TUART_Registers;
    FOnINT: TISR_UART;

    procedure Config(DataBits: TDATABITS; Parity: TPARITY; StopBits: TSTOPBITS);
  public
    constructor Create(PinTX, PinRX: TPIN; UARTx: TUART);
    destructor Destroy; override;

    procedure Start(BaudRate: DWord);
    procedure Stop;
    procedure Send(Data: AnsiString; Size: Word);

  public
    property OnINT: TISR_UART write FOnINT;
  end;

implementation

  function uart_init(var uart: TUART_Registers; Baudrate: DWord): DWord; cdecl; external;
  procedure uart_deinit(var uart: TUART_Registers); cdecl; external;
  function uart_set_baudrate(var uart: TUART_Registers; Baudrate: DWord): DWord; cdecl; external;

constructor CUART.Create(PinTX, PinRX: TPIN; UARTx: TUART);
begin
  inherited Create;

  CHW.SetAF(PinTX, TAF.AFUART);
  CHW.SetAF(PinRX, TAF.AFUART);

  case UARTx of
  TUART.UART_0: FREG:= Pointer(UART0_BASE);
  TUART.UART_1: FREG:= Pointer(UART1_BASE);
  end;

  Config(TDATABITS.EIGHT, TPARITY.NONE, TSTOPBITS.ONE);

  CHW.Masked(FREG^.cr, ($0 shl 15) + ($0 shl 14), $00004000 + $00008000);
  CHW.Masked(FREG^.lcr_h, $1 shl 4, $00000010); //FIFO

  FREG^.imsc:= ($1 shl 5) or ($1 shl 4);
  CHW.Masked(FREG^.ifls, 0 << 3, $00000038); //RX INT
  //CHW.Masked(FREG^.ifls, 0 << 0, $00000007);
end;

destructor CUART.Destroy;
begin
  uart_deinit(FREG^);
  CHW.Release(Self);
  inherited Destroy;
end;

procedure CUART.Config(DataBits: TDATABITS; Parity: TPARITY; StopBits: TSTOPBITS);
begin
  CHW.Masked(FREG^.lcr_h,
    (DWord(DataBits) shl 5) + (DWord(StopBits) shl 3) + (DWord(Parity) shl 1),
    $00000060 + $00000008 + $00000002 + $00000004);
end;

procedure CUART.Start(BaudRate: DWord);
begin
  uart_init(FREG^, Baudrate);
  while (FREG^.cr and $00000001) <> 1 do ;
end;

procedure CUART.Stop;
begin
  uart_deinit(FREG^);
end;

procedure CUART.Send(Data: AnsiString; Size: Word);
var I: Word;
begin
  for I:= 1 to Size do
  begin
    while (FREG^.fr and $00000020) <> 0 do ;
    FREG^.dr:= DWord(Data[I]);
  end;
end;

procedure UART0_IRQHandler;
begin

end;

procedure UART1_IRQHandler;
begin

end;

end.

